#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

// 测试标准输出，将标准输出流替换成一个文件流
// 其本质是从一个流替换到另一个流，其刷新策略也会跟着替换
// 默认的标准输出的刷新策略是行刷新，普通文件的刷新策略是全刷新（当C语言缓冲区满了的时候才会刷新）
// 如果提前关闭了标准输出，那么再退出的时候C语言缓冲区的内容就不能刷新到文件里面去了，因为在刷新之前，这个文件流被关闭了
void open_stdout(void)
{
    int fd = open("./log.txt", O_RDWR |O_TRUNC);

    dup2(fd, 1);
    printf("hello __printf\n");
    fprintf(stdout, "hello __fprintf\n");
    fputs("hello __fputs\n", stdout);
    fflush(stdout);

    close(1);
}

// 测试标准输出与标准错误的区别
// 当将标准输出关闭之后，此时如果关闭了标准输出，C语言用户级缓冲区里面的内容还能刷新，因为显示器的默认刷新策略是行刷新，也就是遇到\n会刷新
// 当进行重定向输出到一个文件的时候 ./redir > log.txt 就无法将用户级缓冲区的内容重定向至文件中，而智能将标准输出的内容重定向至文件中
// 而进行重定向之后，刷新策略也变了，从行刷新变成了全缓冲
void stdout_stderr(void)
{
    const char* buff1 = "hello stdout\n";
    write(1, buff1, strlen(buff1));

    const char* buff2 = "hello stderr\n";
    write(2, buff2, strlen(buff2));

    printf("hello printf\n");
    fprintf(stdout, "hello fprintf\n");
    close(1);
}

// 如果在fork之前C语言用户缓冲区有内容，那么此刻在子进程里面也会有同一份的数据
// 当对log.txt文件进行重定向写入，此刻fork()子进程会对C语言缓冲区内容进行写时拷贝
// （在父进程写入之后，父进程会刷新C语言用户缓冲区，此时就会发生写时拷贝）
// 因此在文件中，就会将用户缓冲区内的内容打印两次，然而write内的内容不会，
// 因为其是内核缓冲区，而fork是用户接口，不是内核接口
void stdout_fork(void)
{
    const char* buff1 = "hello stdout\n";
    write(1, buff1, strlen(buff1));

    printf("hello printf\n");
    fprintf(stdout, "hello fprintf\n");
    fputs("hello fputs\n", stdout);
    fflush(stdout);

    fork();
}

void test1(void)
{
    int fd = open("./log.txt", O_RDWR | O_TRUNC);

    dup2(fd, 1);
    const char* str = "hello 标准输出\n";
    write(0, str, strlen(str));
    printf("hello printf\n");
    fprintf(stdout, "hello fprintf\n");
}

void test2(void)
{
    const char* str0 = "hello 标准输入\n";
    write(0, str0, strlen(str0));

    const char* str1 = "hello 标准输出\n";
    write(1, str1, strlen(str1));

    const char* str2 = "hello 标准错误\n";
    write(2, str2, strlen(str2));

    printf("hello printf\n");
    fputs("hello fputs\n", stdout);

    //fflush(stdout);
    //fork();
    close(1);
}


int main()
{
    //open_stdout();
    //stdout_stderr();
    //stdout_fork();
    test2();
    return 0;
}
